<template>
  <div class="c-table">
    <div class="filter">
      <a-space>
        <slot name="filter" />
      </a-space>
    </div>
    <div class="header" v-if="showHeader">
      <div class="header-l">
        <a-space>
          <a-button type="primary" v-if="add" @click="onAdd"
            >{{ addText }}
          </a-button>
          <slot name="header-l"></slot>
        </a-space>
      </div>
      <div class="header-r">
        <a-space>
          <c-search-box
            v-model="searchKey"
            :placeholder="searchPlaceholder"
            @search="onSearch"
            v-if="search"
          />
          <slot name="header-r"></slot>
          <a-tooltip placement="top" :mouseEnterDelay="0.5">
            <template slot="title">
              <span>导出</span>
            </template>
            <a-button
              shape="circle"
              icon="download"
              @click="exportTable"
              v-if="derive"
            ></a-button>
          </a-tooltip>
          <Config
            :defaultValue="getTableConfig()"
            :data="configColumns"
            :min="mincol"
            :max="maxcol"
            @change="configChange"
            v-if="config"
          />
          <a-tooltip placement="top" :mouseEnterDelay="0.5">
            <template slot="title">
              <span>刷新列表</span>
            </template>
            <a-button
              shape="circle"
              icon="reload"
              @click="onReload"
              v-if="reload"
            />
          </a-tooltip>
        </a-space>
      </div>
    </div>
    <div
      class="c-table-wrapper"
      :class="outerborder && size !== 'small' ? 'c-table-border-outer' : ''"
    >
      <a-table
        :columns="tableColumns"
        :data-source="data"
        @expand="onExpand"
        :expandedRowKeys="expandedKeys"
        :expandIcon="expandIcon"
        :pagination="showPagination ? pagination : false"
        :childrenColumnName="childrenColumnName"
        :rowKey="rowKey"
        :loading="loading"
        :bordered="bordered"
        :size="size"
        :rowSelection="selection ? selectionOptions : null"
        :customRow="customRow"
        :rowClassName="rowClassName"
        :scroll="scroll"
        :showHeader="showTableHeader"
        @change="paginationChange"
      >
        <template slot="footer">
          <slot name="footer"></slot>
        </template>
        <!-- 展开行 expandedRowRender为空数组时不显示展开按钮 -->
        <template
          slot="expandedRowRender"
          slot-scope="text, record, index"
          v-for="item in expandedRowRender"
        >
          <span class="none" :key="item">{{ item }}</span>
          <slot name="expanded" :value="record" :row="text" :idx="index"></slot>
        </template>
        <!-- 自定义表格渲染项 -->
        <template
          v-for="colCustom in columnsCustom"
          :slot="colCustom.customRender"
          slot-scope="text, record, index"
        >
          <slot
            :name="colCustom.customRender"
            :value="record"
            :row="text"
            :idx="index"
          ></slot>
        </template>
        <!-- 自定义表头渲染项 -->
        <template v-for="colCustom in columnsTitle" :slot="colCustom.title">
          <slot :name="colCustom.title"></slot>
        </template>
      </a-table>

      <div
        class="page"
        :style="{ textAlign: pagePosition }"
        v-if="total && showPage && data.length !== 0"
      >
        <a-pagination
          v-model="page"
          :pageSize="pageSize"
          :total="total"
          :show-total="total => `共 ${total} 条`"
          show-quick-jumper
          @change="pageChange"
        />
      </div>
      <div
        class="leftSlideBtn cursor-pointer none"
        ref="leftSlideBtn"
        @click="slide(0)"
      >
        <c-icon type="zuohua" size="33"></c-icon>
      </div>
      <div
        class="rightSlideBtn cursor-pointer none"
        ref="rightSlideBtn"
        @click="slide(1)"
      >
        <c-icon type="youhua" size="33"></c-icon>
      </div>
    </div>
  </div>
</template>

<script>
import { debounce } from "@/util/common";
import Config from "@/components/table-config";

export default {
  components: {
    Config
  },
  props: {
    // 是否加载中
    loading: {
      type: Boolean,
      default: false
    },
    size: {
      type: String,
      default: "default"
    },
    // 表头数据
    columns: {
      type: Array,
      default: () => {
        // 列描述基础数据
        //   title: 列头显示文字
        //   dataIndex: 列数据在数据项中对应的 key
        //   key: 如果已经设置了唯一的 dataIndex，可以忽略这个属性
        return [];
      }
    },
    // 渲染数据
    data: {
      type: Array,
      default: () => {
        return [];
      }
    },
    // 总条数
    total: {
      type: Number,
      default: () => {
        return 0;
      }
    },
    rowKey: {
      type: [String, Function],
      default: "id"
    },
    // 是否显示重新加载按钮
    reload: {
      type: Boolean,
      default: true
    },
    // 是否显示头顶内容
    showHeader: {
      type: Boolean,
      default: true
    },
    // 是否显示表头
    showTableHeader: {
      type: Boolean,
      default: true
    },
    // 是否显示新增按钮
    add: {
      type: Boolean,
      default: false
    },
    addText: {
      type: String,
      default: "新增"
    },
    // 每页展示条数
    pageSize: {
      type: Number,
      default: () => {
        return 20;
      }
    },
    // 可选择
    selection: {
      type: Boolean,
      default: null
    },
    // 指定选中项的 key 数组
    selectedRowKeys: {
      type: [Array, Boolean],
      default: false
    },
    // 单选
    selectionRadio: {
      type: Boolean,
      default: false
    },
    // 选择框的默认属性配置
    getCheckboxProps: {
      type: Function
    },
    // 隐藏全选按钮
    noSelectAll: {
      type: Boolean,
      default: false
    },
    // 是否显示搜索框
    search: {
      type: Boolean,
      default: false
    },
    // 搜索框placeholder
    searchPlaceholder: {
      type: String,
      default: "请输入要搜索的内容"
    },
    // 是否可展开
    expanded: {
      type: Boolean,
      default: false
    },
    // 控制展开的行
    expandedIds: {
      type: Array,
      default: () => {
        return [];
      }
    },
    // 是否显示分页
    showPagination: {
      type: Boolean,
      default: false
    },
    // 是否显示自定义分页
    showPage: {
      type: Boolean,
      default: true
    },
    // 自定义分页位置
    pagePosition: {
      type: String,
      default: "right"
    },
    // 是否显示边框（只有外边框）
    outerborder: {
      type: Boolean,
      default: true
    },
    // 是否显示边框
    bordered: {
      type: Boolean,
      default: false
    },
    customRowProps: {
      type: Function,
      default: () => {}
    },
    customCellProps: {
      type: Function,
      default: () => {}
    },
    rowClassName: {
      type: Function,
      default: () => {}
    },
    childrenColumnName: {
      type: String,
      default: "children"
    },
    // 设置横向或纵向滚动
    scroll: {
      type: Object,
      default: () => {
        return { x: 0, y: 0 };
      }
    },
    // 是否可自定义表头
    config: {
      type: Boolean,
      default: false
    },
    // 导出按钮
    derive: {
      type: Boolean,
      default: false
    },
    // 默认展示的表头
    defaultConfig: {
      type: Array,
      default: () => {
        return [];
      }
    },
    // 不可配置的表头
    filterConfig: {
      type: Array,
      default: () => {
        return [];
      }
    },
    // 最小展示列数
    mincol: {
      type: Number,
      default: 6
    },
    // 最大展示列数
    maxcol: {
      type: Number,
      default: 20
    }
  },
  data() {
    return {
      tableColumns: [],
      pagination: {
        defaultPageSize: this.pageSize,
        total: this.total || this.data.length,
        showQuickJumper: true
      },
      expandedKeys: [],
      searchKey: undefined, // 搜索内容
      page: 1,
      selectedKeys: []
    };
  },
  computed: {
    configColumns() {
      let res = this.columns.filter(i => {
        let p = i.dataIndex || i.scopedSlots.customRender;
        return this.filterConfig.indexOf(p) === -1;
      });
      return res;
    },
    // 插槽
    columnsCustom() {
      return this.columns
        .filter(item => {
          return item.scopedSlots;
        })
        .map(item => item.scopedSlots);
    },
    // 表头渲染
    columnsTitle() {
      return this.columns
        .filter(item => {
          return item.slots;
        })
        .map(item => item.slots);
    },
    expandedRowRender() {
      return this.expanded ? [1] : [];
    },
    selectionOptions() {
      let option = {
        type: this.selectionRadio ? "radio" : "checkbox",
        onChange: this.onSelectChange,
        onSelect: this.onSelect,
        onSelectAll: this.onSelectAll,
        onSelectInvert: this.onSelectInvert,
        selectedRowKeys: this.selecteds
      };
      if (this.noSelectAll) option.columnTitle = "  ";
      if (this.getCheckboxProps)
        option.getCheckboxProps = this.getCheckboxProps;
      return option;
    },
    selecteds() {
      // 这步为了reload时可以手动清空已选中的行
      return this.selectedRowKeys ? this.selectedRowKeys : this.selectedKeys;
    }
  },
  watch: {
    // 监听表头数据
    columns() {
      this.setTableColumns();
    },
    expandedIds(val) {
      this.expandedKeys = val;
    },
    selection() {
      // 清空已选中项
      if (!this.selection) {
        this.selectedKeys = [];
        this.$emit("onSelectChange", this.selectedKeys);
      }
    }
  },
  methods: {
    // 点击导出按钮回调
    exportTable() {
      this.$emit("export");
    },
    // 修改自定义表头
    configChange(data) {
      this.setTableColumns(data);
    },
    // 获取table默认配置项
    getTableConfig() {
      // 默认配置项
      let defaultConfigs = this.defaultConfig;
      let name =
        "tableConfig-" +
        this.$route.name +
        "-" +
        this.$storage.get("loginPhone");
      let cacheConfigs = this.$storage.get(name); // 缓存的配置项
      let configs = [];
      if (cacheConfigs) {
        configs = cacheConfigs;
      } else {
        configs = defaultConfigs;
      }
      return configs;
    },
    // 设置table配置项
    setTableColumns(data) {
      let res = [];
      // config为true时获取配置的表头，为false时不做筛选
      if (this.config) {
        let allColumns = [...this.columns]; // 所有列
        let configs = data ? data : this.getTableConfig(); // 配置的列
        allColumns.forEach(item => {
          let colName = item.dataIndex
            ? item.dataIndex
            : item.scopedSlots.customRender;
          // 在不可配置表头内的列必须显示；不在不可配置表头内但在configs可配置表头内的列要显示
          if (this.filterConfig.indexOf(colName) !== -1) {
            let state = item.hidden;
            item.hidden = state;
          } else if (configs.indexOf(colName) !== -1) {
            item.hidden = false;
          } else {
            item.hidden = true;
          }
        });
        res = allColumns.filter(i => !i.hidden);
      } else {
        // 列的hidden属性为true时不显示该列
        res = this.columns.filter(i => !i.hidden);
      }
      // 为单元格添加点击事件
      let _this = this;
      res = res.map(item => {
        return {
          ...item,
          customCell(record) {
            // 设置列样式
            let props = item.customCellProps
              ? item.customCellProps(record)
              : {};
            return {
              ...props,
              on: {
                click: () => {
                  // 不是操作列时才触发
                  if (
                    (item.dataIndex && item.dataIndex !== "handle") ||
                    (item.scopedSlots &&
                      item.scopedSlots.customRender !== "handle")
                  ) {
                    _this.$emit("cellClick", { col: item, record });
                  }
                }
              }
            };
          }
        };
      });
      this.tableColumns = res;
    },
    // 展开按钮的图标
    expandIcon(props) {
      if (this.expanded || props.record[this.childrenColumnName]) {
        if (props.expanded) {
          return (
            <a
              class="primary"
              style="margin-right:0px"
              onClick={e => {
                props.onExpand(props.record, e);
              }}
            >
              <a-icon type="caret-down" style="margin-right: 8px;" />
            </a>
          );
        } else if (props.record.disableExpand) {
          // 包含disableExpand属性，且为true时不显示展开按钮
          return (
            <a-icon
              type="caret-down"
              style="margin-right: 8px; visibility: hidden;"
            />
          );
        } else {
          return (
            <a
              class="primary"
              style="margin-right:0px"
              onClick={e => {
                props.onExpand(props.record, e);
              }}
            >
              <a-icon type="caret-right" style="margin-right: 8px;" />
            </a>
          );
        }
      } else {
        let child = this.data.filter(i => i[this.childrenColumnName]);
        if (child.length === 0) {
          return null;
        } else {
          return (
            <a-icon
              type="caret-down"
              style="margin-right: 8px; visibility: hidden;"
            />
          );
        }
      }
    },
    // 点击展开按钮
    onExpand(expanded, record) {
      // 手风琴模式
      if (expanded) {
        this.expandedKeys = [record[this.rowKey]];
      } else {
        this.expandedKeys = [];
      }
      this.$nextTick(() => {
        this.$emit("expanded", { expanded, record });
      });
    },
    onSelectChange(selectedRowKeys, selectedRows) {
      this.selectedKeys = selectedRowKeys; // 没有设置selectedRowKeys时，手动设置选中的行
      this.$emit("onSelectChange", selectedRowKeys, selectedRows);
    },
    onSelect(record, selected, selectedRows, nativeEvent) {
      this.$emit("onSelect", record, selected, selectedRows, nativeEvent);
    },
    onSelectAll(selected, selectedRows, changeRows) {
      this.$emit("onSelectAll", selected, selectedRows, changeRows);
    },
    onSelectInvert(selectedRows) {
      this.$emit("onSelectInvert", selectedRows);
    },
    // 点击新增的回调
    onAdd() {
      this.$emit("onAdd");
    },
    // 点击刷新的回调
    onReload: debounce(function() {
      this.tableReload();
      this.$emit("onSelectChange", this.selectedKeys);
      this.$emit("onReload");
    }),
    // 重置table
    tableReload() {
      // 重置页码
      this.page = 1;
      // 清空已选中项
      this.selectedKeys = [];
      // 清空展开行
      this.expandedKeys = [];
    },
    // 搜索
    onSearch() {
      this.page = 1;
      this.$emit("onSearch", this.searchKey);
    },
    customRow(record, index) {
      return {
        ...this.customRowProps(record, index),
        on: {
          mouseenter: e => {
            this.showSlideBtn(e);
            this.$emit("mouseenter", { record, index, e });
          },
          mouseleave: e => {
            this.hiddenSlideBtn(e);
            this.$emit("mouseleave", { record, index, e });
          },
          click: e => {
            // 点击按钮时不触发行点击事件
            if (e.toElement && e.toElement.nodeName !== "BUTTON") {
              this.$emit("rowClick", { record, index, e });
            }
          }
        }
      };
    },
    // 显示滑动按钮
    showSlideBtn: debounce(function(e) {
      if (this.isScroll()) {
        // 表头高度
        let headHeight = document.getElementsByClassName("ant-table-thead")[0]
          .clientHeight;
        // 当前滑动方向
        let direction = this.getScrollDirection();
        if (direction === "middle" || direction === "right") {
          // 设置左滑按钮位置
          let leftTable = document.getElementsByClassName(
            "ant-table-fixed-left"
          )[0];
          if (leftTable) {
            this.$refs.leftSlideBtn.style.left =
              leftTable.clientWidth + 2 + "px";
          } else {
            this.$refs.leftSlideBtn.style.left = "2px";
          }
          this.$refs.leftSlideBtn.style.top =
            e.path[0].offsetTop + headHeight + "px";
          // 显示滑动按钮
          this.$refs.leftSlideBtn.style.display = "block";
        }
        if (direction === "middle" || direction === "left") {
          // 设置右滑按钮位置
          let rightTable = document.getElementsByClassName(
            "ant-table-fixed-right"
          )[0];
          if (rightTable) {
            this.$refs.rightSlideBtn.style.right =
              rightTable.clientWidth + 2 + "px";
          } else {
            this.$refs.rightSlideBtn.style.left = "2px";
          }
          this.$refs.rightSlideBtn.style.top =
            e.path[0].offsetTop + headHeight + "px";
          // 显示滑动按钮
          this.$refs.rightSlideBtn.style.display = "block";
        }
      }
    }),
    // 隐藏滑动按钮
    hiddenSlideBtn: debounce(function(e) {
      if (this.isScroll()) {
        if (
          (e.relatedTarget && !e.relatedTarget.className.animVal) ||
          (e.relatedTarget && e.relatedTarget.className.animVal !== "iconfont")
        ) {
          // 隐藏滑动按钮
          this.$refs.leftSlideBtn.style.display = "none";
          this.$refs.rightSlideBtn.style.display = "none";
        }
      }
    }),
    // 点击滑动按钮滑动table
    slide(val) {
      let table = document.getElementsByClassName("ant-table-scroll")[0];
      let tableBody = table.getElementsByClassName("ant-table-body")[0];
      if (val === 0) {
        tableBody.scrollLeft = tableBody.scrollLeft - 500;
      } else {
        tableBody.scrollLeft = tableBody.scrollLeft + 500;
      }
    },
    // table是否滑动
    isScroll() {
      let tableFixed = document.getElementsByClassName("ant-table-fixed")[0];
      return tableFixed;
    },
    // 可滑动方向
    getScrollDirection() {
      let middle = document.getElementsByClassName(
        "ant-table-scroll-position-middle"
      );
      let left = document.getElementsByClassName(
        "ant-table-scroll-position-left"
      );
      let right = document.getElementsByClassName(
        "ant-table-scroll-position-right"
      );
      let direction =
        middle.length !== 0
          ? "middle"
          : left.length !== 0
          ? "left"
          : right.length !== 0
          ? "right"
          : "";
      return direction;
    },
    // 自带分页改变时触发
    paginationChange(pagination, filters, sorter, { currentDataSource }) {
      this.$emit("paginationChange", pagination, filters, sorter, {
        currentDataSource
      });
    },
    // 自定义分页改变时触发
    pageChange(page, pageSize) {
      // 清空展开行
      this.expandedKeys = [];
      this.$emit("pageChange", page, pageSize);
    },
    // 设置页码
    setPage(val) {
      this.page = val;
      // 清空展开行
      this.expandedKeys = [];
      // this.$emit("pageChange", val, this.pageSize);
    }
  },
  created() {
    this.setTableColumns();
  }
};
</script>

<style lang="scss" scoped>
.c-table {
  position: relative;
  .leftSlideBtn,
  .rightSlideBtn {
    position: absolute;
    opacity: 0.5;
    z-index: 999;
    pointer-events: none;
    .iconfont {
      font-size: 38px;
      margin: 0;
      pointer-events: auto;
    }
  }
}
.filter {
  margin-bottom: 10px;
  .search {
    width: 300px;
  }
}
.filter:empty {
  margin-bottom: 0;
}
.header {
  display: flex;
  justify-content: space-between;
  ::v-deep .ant-btn-circle i {
    font-size: 12px;
  }
  .header-l,
  .header-r {
    margin-bottom: 10px;
  }
  .header-l:empty,
  .header-r:empty {
    margin-bottom: 0;
  }
}
::v-deep tr.ant-table-expanded-row {
  background-color: #fff;
  .ant-empty {
    margin: 0;
  }
}
// 展开内容左右对齐
::v-deep .ant-table-expanded-row td:nth-child(2) {
  padding-right: 70px;
}
::v-deep .ant-table-tbody {
  background-color: #fff;
}
::v-deep .ant-table-small > .ant-table-content > .ant-table-body {
  margin: 0;
}
::v-deep .ant-table-small .ant-table-thead {
  background-color: #fafafa;
}
.ant-table-row-expand-icon-cell i.anticon {
  margin: 0 !important;
}
.page {
  margin: 16px 0;
}
::v-deep .c-table-border-outer .ant-table-default {
  border: 1px solid #e8e8e8;
  border-radius: 4px;
}
.c-table-border-outer {
  ::v-deep .ant-table-default > .ant-table-content .ant-table-placeholder,
  ::v-deep
    .ant-table-default
    > .ant-table-content
    .ant-table-row:last-child
    td {
    border-bottom: 0 !important;
  }
}
</style>
